package cn.com.zero.web;


import cn.com.zero.base.config.ReturnCodeConfig;
import cn.com.zero.base.vo.ResponseVO;
import cn.hutool.core.util.StrUtil;
import org.springframework.core.MethodParameter;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Locale;

/**
 * @author zhoupeng
 * @version 1.0.0
 * @Description 对所有 controller 扩展，该类作用：统一处理返回包为 {@link ResponseVO} 结构
 * @createTime 2022-07-11
 */
// 指定cn.com.zero 包及其子包下的所有 Controller 都被该@RestControllerAdvice 管理
@RestControllerAdvice("cn.com.zero")
public class GlobalControllerAdvice implements ResponseBodyAdvice<Object> {
    /**
     * 返回码配置
     */
    private ReturnCodeConfig returnCodeConfig;

    public GlobalControllerAdvice(ReturnCodeConfig returnCodeConfig) {
        this.returnCodeConfig = returnCodeConfig;
    }

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 目前只处理转换器为 MappingJackson2HttpMessageConverter 的内容
        return converterType != null && StrUtil.equals(converterType.getName(), MappingJackson2HttpMessageConverter.class.getName());
    }

    /**
     * 统一封装处理返回包
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body instanceof ResponseVO) {
            // 格式化返回码
            ResponseVO responseVO = (ResponseVO) body;
            String codeMessage = returnCodeConfig.getMessage(String.valueOf(responseVO.getCode()),
                    responseVO.getArgs(), getRequestLanguage(request));
            responseVO.setMessage(StrUtil.emptyToDefault(responseVO.getMessage(), codeMessage));
            return body;
        }
        if (body instanceof ResponseEntity) {
            return body;
        }
        if (body instanceof FileSystemResource) {
            return body;
        }
        return ResponseVO.success(body);
    }

    /**
     * 获取请求中的语言标识
     *
     * @param request 请求
     * @return 语言标识，如 zh-CN
     */
    private String getRequestLanguage(@NotNull ServerHttpRequest request) {
        List<Locale> localeList = request.getHeaders().getAcceptLanguageAsLocales();
        if (localeList != null && localeList.size() > 0) {
            return localeList.get(0).toLanguageTag();
        }
        return "";
    }

}
